/*-
 * Copyright (c) 2007 Microsoft
 * All rights reserved.
 */

#pragma once

namespace Microsoft{
    namespace ComputeCluster{
        namespace MpiNet{
            using namespace System::Runtime::InteropServices;
            using namespace System;

            ///<summary>
            ///Represent a MPI Communicator supports using .Net object to communicate.
            ///Primitive type, sequence and explict layout structure and serializable objects are supported.
            ///</summary>
            public ref class Comm
            {
            private:
                int rank;
                int size;

            internal:
                Comm(int handle);
                int handle;

            public:
                literal int AnySource = MPI_ANY_SOURCE;
                literal int AnyTag = MPI_ANY_TAG;

                ///<summary>
                ///Communicator contains all of the processes
                ///</summary>
                static Comm^ World;

                ///<summary>
                ///Communicator contains only the calling process
                ///</summary>
                static Comm^ Self;

                property int Rank{int get();}

                property int Size{int get();}

                generic<typename T> void Bcast(int root, T% value);
                generic<typename T> void Bcast(int root, array<T>^ data, int index, int length);

                generic<typename T> IAsyncResult^ BeginSend(int target, T data, int tag, AsyncCallback^ callback);
                generic<typename T> IAsyncResult^ BeginSend(int target, array<T>^ data, int tag, int index, int length, AsyncCallback^ callback);
                void EndSend(IAsyncResult^ result);

                generic<typename T> void Send(int target, T data, int tag);
                generic<typename T> void Send(int target, array<T>^ data, int tag, int index, int length);

                generic<typename T> void Receive(int target, [Out] T% data, int tag);
                generic<typename T> void Receive(int target, array<T>^ data, int tag, int index, int length);

                generic<typename T> void Gather(int root, T send, array<T>^ data);
                generic<typename T> void Scatter(int root, [Out] T% send, array<T>^ data);

                void Barrier();

                generic<typename T> void Reduce(int root, T input, [Out] T% output, int op);
                generic<typename T> void Reduce(int root, array<T>^ input, array<T>^ output, int op);

                generic<typename T> void AllReduce(array<T>^ input, array<T>^ output, int op);
            };
        }
    }
}
